﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using System.Web;
using System.Globalization;
using System.Net;
using System.IO;
using System.Collections;

namespace SPResourceTranslator
{
    public static class Translate
    {
        public enum LangPair
        {
            EnglishToGerman,
            EnglishToSpanish,
            EnglishToFrench,
            EnglishToDutch,
            EnglishToItalian,
            EnglishToPortuguese,
            EnglishToJapanese,
            EnglishToKorean,
            EnglishToChineseSimplified,
            GermanToEnglish,
            GermanToFrench,
            SpanishToEnglish,
            FrenchToEnglish,
            FrenchToGerman,
            ItalianToEnglish,
            PortugueseToEnglish,
            JapaneseToEnglish,
            KoreanToEnglish,
            ChineseSimplifiedToEnglish
        }

        public static CultureInfo GetCultureInfo(LangPair language)
        {
            CultureInfo cult = null;
            switch (language)
            {
                case (LangPair.ChineseSimplifiedToEnglish):

                    cult = new CultureInfo("en");
                    break;
                case (LangPair.EnglishToDutch):
                    cult = new CultureInfo("nl");
                    break;
                case (LangPair.EnglishToChineseSimplified):
                    cult = new CultureInfo("CN");
                    break;
                case (LangPair.EnglishToFrench):
                    cult = new CultureInfo("fr");
                    break;
                case (LangPair.EnglishToGerman):
                    cult = new CultureInfo("de");
                    break;
                case (LangPair.EnglishToItalian):
                    cult = new CultureInfo("it");
                    break;
                case (LangPair.EnglishToJapanese):
                    cult = new CultureInfo("ja");
                    break;
                case (LangPair.EnglishToKorean):
                    cult = new CultureInfo("ko");
                    break;
                case (LangPair.EnglishToPortuguese):
                    cult = new CultureInfo("pt");
                    break;
                case (LangPair.EnglishToSpanish):
                    cult = new CultureInfo("es");
                    break;
                case (LangPair.FrenchToEnglish):
                    cult = new CultureInfo("en");
                    break;
                case (LangPair.FrenchToGerman):
                    cult = new CultureInfo("de");
                    break;
                case (LangPair.GermanToEnglish):
                    cult = new CultureInfo("en");
                    break;
                case (LangPair.GermanToFrench):
                    cult = new CultureInfo("fr");
                    break;
                case (LangPair.ItalianToEnglish):
                    cult = new CultureInfo("en");
                    break;
                case (LangPair.JapaneseToEnglish):
                    cult = new CultureInfo("en;");
                    break;
                case (LangPair.KoreanToEnglish):
                    cult = new CultureInfo("en");
                    break;
                case (LangPair.PortugueseToEnglish):
                    cult = new CultureInfo("en");
                    break;
                case (LangPair.SpanishToEnglish):
                    cult = new CultureInfo("en");
                    break;
                default:
                    cult = new CultureInfo("en");
                    break;
            }

            return cult;
        }

        public static string GoolgeTranslate(this String original, LangPair fromto)
        {
            return GetTranslatedText(original, fromto);
        }

        private static string GetTranslatedText(string textToTranslate, LangPair langPair)
        {
            string strLangPair = String.Empty;

            switch (langPair)
            {
                case (LangPair.ChineseSimplifiedToEnglish):
                    strLangPair = "zh-CN%7Cen";
                    break;
                case (LangPair.EnglishToDutch):
                    strLangPair = "zh-CN%7Cnl";
                    break;
                case (LangPair.EnglishToChineseSimplified):
                    strLangPair = "en%7Czh-CN";
                    break;
                case (LangPair.EnglishToFrench):
                    strLangPair = "en%7Cfr";
                    break;
                case (LangPair.EnglishToGerman):
                    strLangPair = "en%7Cde";
                    break;
                case (LangPair.EnglishToItalian):
                    strLangPair = "en%7Cit";
                    break;
                case (LangPair.EnglishToJapanese):
                    strLangPair = "en%7Cja";
                    break;
                case (LangPair.EnglishToKorean):
                    strLangPair = "en%7Cko";
                    break;
                case (LangPair.EnglishToPortuguese):
                    strLangPair = "en%7Cpt";
                    break;
                case (LangPair.EnglishToSpanish):
                    strLangPair = "en%7Ces";
                    break;
                case (LangPair.FrenchToEnglish):
                    strLangPair = "fr%7Cen";
                    break;
                case (LangPair.FrenchToGerman):
                    strLangPair = "fr%7Cde";
                    break;
                case (LangPair.GermanToEnglish):
                    strLangPair = "de%7Cen";
                    break;
                case (LangPair.GermanToFrench):
                    strLangPair = "de%7Cfr";
                    break;
                case (LangPair.ItalianToEnglish):
                    strLangPair = "it%7Cen";
                    break;
                case (LangPair.JapaneseToEnglish):
                    strLangPair = "ja%7Cen;";
                    break;
                case (LangPair.KoreanToEnglish):
                    strLangPair = "ko%7Cen";
                    break;
                case (LangPair.PortugueseToEnglish):
                    strLangPair = "pt%7Cen";
                    break;
                case (LangPair.SpanishToEnglish):
                    strLangPair = "es%7Cen";
                    break;
                default:
                    strLangPair = "en%7Cde";
                    break;
            }

            string url = "http://translate.google.com/translate_t?text=" + textToTranslate + "&langpair=" + strLangPair;
            string source = StringGetWebPage(url);
            string[] stuff = GetTagsByName("span", source);
            object oresult = stuff.SingleOrDefault(item => item.Contains("result_box"));
            string result = textToTranslate;
            if (oresult != null)
            {
                oresult = oresult.ToString().Replace("result_box", "'result_box'")+"</span>";
                XElement xresult = XElement.Parse(oresult.ToString());
                result = HttpUtility.HtmlDecode(xresult.Value);
            }
            return result;
        }

        private static string StringGetWebPage(String uri)
        {
            const int bufSizeMax = 65536;
            // max read buffer size conserves memory    
            const int bufSizeMin = 8192;
            // min size prevents numerous small reads    
            StringBuilder sb;
            // A WebException is thrown if HTTP request fails    
            try
            {
                // Create an HttpWebRequest using WebRequest.Create (see .NET docs)!        
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
                // Execute the request and obtain the response stream        
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                Stream responseStream = response.GetResponseStream();
                // Content-Length header is not trustable, but makes a good hint.       
                // Responses longer than int size will throw an exception here!       
                int length = (int)response.ContentLength;
                // Use Content-Length if between bufSizeMax and bufSizeMin        
                int bufSize = bufSizeMin;
                if (length > bufSize)
                    bufSize = length > bufSizeMax ? bufSizeMax : length;
                // Allocate buffer and StringBuilder for reading response       
                byte[] buf = new byte[bufSize];
                sb = new StringBuilder(bufSize);
                // Read response stream until end        
                while ((length = responseStream.Read(buf, 0, buf.Length)) != 0)
                    sb.Append(Encoding.UTF8.GetString(buf, 0, length));
            }
            catch (Exception ex)
            {
                sb = new StringBuilder(ex.Message);
            }
            return sb.ToString();
        }

        private static string StripComments(string strSource)
        {
            Regex r
                = new Regex(GetExpressionForTagContents("!"));
            return (r.Replace(strSource, ""));
        }

        public static string[] GetTagsByName(string TagName, string Source)
        {
            RegexOptions opts
                = RegexOptions.IgnoreCase | RegexOptions.Singleline;
            string strPattern;

            //Normally we will ignore comments
            if (TagName != "!")
            {
                Source = StripComments(Source);
                strPattern
                    = "<(?<TagName>" + TagName + @")(>|\s+[^>]*>)";
            }
            else
                strPattern
                    = "<(?<TagName>" + TagName + @")--";

            //Find the beginning position of each matching tag
            MatchCollection mc
                = Regex.Matches(Source, strPattern, opts);

            //Grab the contents of each matching tag 
            ArrayList strTagContents = new ArrayList();
            foreach (Match m in mc)
            {
                strTagContents.Add(GetTagByName(TagName,
                    Source.Substring
                     (m.Groups["TagName"].Index - 1)));
            }
            return ((string[])strTagContents.ToArray(typeof(String)));
        }

        private static string GetTagByName(string strTagName, string strSource)
        {
            string strPatternTag = GetExpressionForTagContents(strTagName);
            string strPatternTagNoClose = "<" + strTagName + @"(>|\s+[^>]*>)[^<]";
            RegexOptions opts = RegexOptions.IgnoreCase | RegexOptions.Singleline;
            Match m;
            string strGetTagByName;

            m = System.Text.RegularExpressions.Regex.Match(strSource, strPatternTag, opts);
            if (m.Value == "")
            {
                m = System.Text.RegularExpressions.Regex.Match(strSource, strPatternTagNoClose, opts);
                if (m == null)
                    strGetTagByName = strSource;
                else
                    strGetTagByName = m.Value;
            }
            else
                strGetTagByName = m.Value;
            return (strGetTagByName);
        }

        private static string GetExpressionForTagContents(string strTagName)
        {
            string strPatternTag;
            if (strTagName == "!")
                strPatternTag = "<!.*?-->";
            else
                if (string.Compare(strTagName, "!doctype", true) == 0)
                    strPatternTag = "<!doctype.*?>";
                else
                    if (String.Compare(strTagName, "br", true) == 0)
                        strPatternTag = @"<br\s*/?\s*>";
                    else
                        strPatternTag
                            = @"<(" + strTagName + @")(>|\s+[^>]*>).*?</\1\s*>";
            return (strPatternTag);
        }
    }
}
